package edu.gatech.cs2340.teamrocket.model.pokemon;

import java.io.Serializable;
import edu.gatech.cs2340.teamrocket.control.exception.ItemHasNoEffectException;
import edu.gatech.cs2340.teamrocket.model.pokemon.ailments.Ailment;
import edu.gatech.cs2340.teamrocket.model.pokemon.ailments.AilmentFactory;
import edu.gatech.cs2340.teamrocket.model.pokemon.ailments.NoAilment;

/**
 * Represents a Pokemon team member.
 *
 * @author Joe Tacheron
 */
public class Pokemon implements Serializable {

    public static final int MAX_HEALTH = 100;
    public static final int MAX_PP = 40;

    private String name;
    private int health;
    private int pp;
    private Ailment ailment;
    private boolean fainted;
    private boolean canMove;

    /**
     * Default constructor. Gives the Pokemon an air of mystique.
     */
    public Pokemon(){
        this("???");
    }

    public Pokemon(String n){
        name = n;
        health = MAX_HEALTH;
        pp = MAX_PP;
        ailment = new NoAilment();
        canMove = true;
    }

    /**
     * Take damage and faint if health hits zero.
     *
     * @param damage the amount of damage to take
     */
    public void takeDamage(int damage){
        health -= damage;
        if(health <= 0){
            faint();
        }
    }

    /**
     * Add health to this Pokemon, as if this Pokemon used a Potion.
     *
     * @param amount amount of health to add
     * @throws ItemHasNoEffectException If this Pokemon is fainted or has full health.
     */
    public void heal(int amount) throws ItemHasNoEffectException {
        if(fainted)
            throw new ItemHasNoEffectException("You cannot heal a fainted Pokemon with a Potion.");
        if(health == MAX_HEALTH)
            throw new ItemHasNoEffectException("This Pokemon already has full health.");
        health += amount;
        if(health > MAX_HEALTH)
            health = MAX_HEALTH;
    }

    /**
     * Heal an Ailment, as if this Pokemon used a FullHeal.
     *
     * @throws ItemHasNoEffectException If this Pokemon is fainted, has no
     * ailment, or has an ailment that is not healed by a Full Heal.
     */
    public void healAilment() throws ItemHasNoEffectException {
        if(fainted)
            throw new ItemHasNoEffectException("You cannot heal a fainted Pokemon with a FullHeal.");
        if(ailment == AilmentFactory.NONE)
            throw new ItemHasNoEffectException("You have no Ailment.");
        if(ailment.healedByFullHeal()){
            ailment = AilmentFactory.NONE;
        }
        else{
            throw new ItemHasNoEffectException("This ailment cannot be healed by a FullHeal");
        }
    }

    /**
     * Add PP. Keeps PP less than or equal to max.
     *
     * @param amount amount of PP to add
     */
    public void addPP(int amount){
        pp += amount;
        if(pp > MAX_PP)
            pp = MAX_PP;
    }

    /**
     * Remove PP. Keeps PP greater than or equal to 0.
     *
     * @param amount amount of PP to remove
     */
    public void removePP(int amount){
        pp -= amount;
        if(pp <= 0)
            faint();
    }

    public String getName(){
        return name;
    }

    public void setName(String aName){
        name = aName;
    }

    public int getHealth() {
        return health;
    }

    public int getPP() {
        return pp;
    }

    public Ailment getAilment(){
        return ailment;
    }

    /**
     * Sets fainted status to true, can move status to true, PP to 0, health to
     * 0, and ailment to none.
     */
    public void faint(){
        fainted = true;
        canMove = true;
        pp = 0;
        health = 0;
        ailment = AilmentFactory.NONE;
    }

    /**
     * Sets fainted status to false, can move status to true, PP to max, health
     * to max, and ailment to none.
     */
    public void revive(){
        fainted = false;
        canMove = true;
        pp = MAX_PP;
        health = MAX_HEALTH;
        ailment = AilmentFactory.NONE;
    }

    public boolean isFainted(){
        return fainted;
    }

    public void setAilment(Ailment a){
        ailment = a;
    }

    public void canMove(boolean b){
        canMove = b;
    }

    public boolean canMove(){
        return canMove;
    }

    /**
     *
     * @return the name of this Pokemon.
     */
    @Override
    public String toString(){
        return name;
    }
}